package org.web.webdisplay.server.biz.impl;

import org.apache.commons.lang3.StringUtils;
import org.web.base.domain.InsertGroup;
import org.web.base.domain.UpdateGroup;
import org.web.base.domain.exception.ResultMessageEnum;
import org.web.base.domain.helper.ServiceExceptionHelper;
import org.web.base.domain.helper.ValidationHelper;
import org.web.webdisplay.sdk.dto.DisplayInfoDTO;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class ListHelper {

    public static <T, ID> ListSplitResult<T> splitList(List<T> list, Function<T, ID> idGetter) {
        List<T> insertList = new ArrayList<>();
        List<T> updateList = new ArrayList<>();
        if (list != null && idGetter != null) {
            for (T item : list) {
                if (item == null) continue;
                if (idGetter.apply(item) == null) {
                    insertList.add(item);
                } else {
                    updateList.add(item);
                }
            }
        }
        // 校验 updateList 中主键是否重复
        Set<ID> updateIdSet = new HashSet<>();
        for (T item : updateList) {
            ID id = idGetter.apply(item);
            if (!updateIdSet.add(id)) {
                // 如果 add 返回 false，说明重复
                throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.DATA_DUPLICATE, "主键信息有重复: " + id);
            }
        }
        return new ListSplitResult<>(insertList, updateList);
    }

    public static <T> void checkListDataValidate(ListSplitResult<T> listSplitResult){
        List<T> insertList = listSplitResult.getInsertList();
        List<T> updateList = listSplitResult.getUpdateList();
        for (T obj : insertList) {
            @SuppressWarnings("unchecked")
            Class<T> clazz = (Class<T>) obj.getClass();
            ValidationHelper.validate(clazz, obj, InsertGroup.class);
        }

        for (T obj : updateList) {
            @SuppressWarnings("unchecked")
            Class<T> clazz = (Class<T>) obj.getClass();
            ValidationHelper.validate(clazz, obj, UpdateGroup.class);
        }
    }


    /**
     * 将List转换为String，使用指定分隔符连接
     * @param list 要转换的List
     * @param delimiter 分隔符
     * @return 连接后的字符串
     */
    public static <T> String listToString(List<T> list, String delimiter) {
        if (list == null || list.isEmpty()) {
            return "";
        }
        return list.stream()
                .map(item -> item != null ? item.toString() : "null")
                .collect(Collectors.joining(delimiter));
    }

    /**
     * 统计列表中每个元素的出现次数
     * @param list 元素列表
     * @return 元素到出现次数的映射
     */
    public static <T> Map<T, Integer> countOccurrences(List<T> list) {
        Map<T, Integer> countMap = new HashMap<>();
        for (T item : list) {
            countMap.put(item, countMap.getOrDefault(item, 0) + 1);
        }
        return countMap;
    }

    /**
     * 查找列表中的重复元素（组合方法）
     * @param list 元素列表
     * @return 重复元素列表
     */
    public static <T> List<T> findDuplicates(List<T> list) {
        return collectDuplicates(countOccurrences(list));
    }

    /**
     * 将重复元素（基于 toString）拼接为字符串
     */
    public static <T> String findDuplicatesByToString(List<T> list, String delimiter) {
        List<T> duplicates = findDuplicates(list);
        return listToString(duplicates,delimiter);
    }

    /**
     * 从统计映射中收集重复元素
     * @param countMap 元素统计映射
     * @return 重复元素列表
     */
    public static <T> List<T> collectDuplicates(Map<T, Integer> countMap) {
        return countMap.entrySet().stream()
                .filter(entry -> entry.getValue() > 1)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
    }


    /***
     * 参数校验
     * @param list, 待校验的数组
     * 1、List 去重校验。
     */
    public static <T> void checkBatchListDuplication(List<T> list) {
        String duplicatesByToString = ListHelper.findDuplicatesByToString(list, "&");
        if (StringUtils.isNotBlank(duplicatesByToString)) {
            throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.DATA_DUPLICATE, duplicatesByToString);
        }
    }
}
